<script>
import { Teleport, h, Fragment } from 'vue'
import popIdUtil from "../common/popIdUtil"
import { createPopper } from '@popperjs/core'
import AScrollable from './AScrollable.vue'
import utils from '../common/utils'

export default {
    components: { AScrollable },
    props: {
        popShown: {
            type: Boolean,
            default: false,
        },
        /**
         * 对齐到target的方式
         */
        popPlacement: {
            type: String,
            default: 'bottom'
        },
        popModifiers: {
            type: Array,
            default: []
        },
        getPopModifiersFunc: {
            type: Function,
            default: null
        },
        useTargetWidth: {
            type: Boolean,
            default: false,
        },
        maxHeight: {
            type: Number,
            default: null
        },
        escToClose: {
            type: Boolean,
            default: true,
        },
    },
    data() {
        return {
            popId: null,
            popInstance: null,
            resizeObserver: new ResizeObserver(this.pinToTarget)
        }
    },
    render() {
        let targetAttrs = Object.assign({
            ref: 'target',
        }, this.$attrs)
        let elList = [h(this.$slots.default()[0], targetAttrs)]
        if (this.popShown) {

            let popRender = null
            if (this.maxHeight > 0) {
                let popStyle = {
                }
                popStyle.maxHeight = `${this.maxHeight}px`
                popStyle.overflowY = 'auto'

                popRender = h(AScrollable, {
                    ref: 'pop',
                    style: popStyle,
                }, this.$slots.pop)
            } else {
                popRender = h(this.$slots.pop()[0], {
                    ref: 'pop',
                })
            }

            elList.push(h(Teleport, {
                to: 'body'
            }, h(Fragment, null, popRender)))
        }
        return elList
    },
    mounted() {
        if (this.popShown) {
            this.onPopShown()
        }
    },
    watch: {
        popShown(val) {
            if (val) {
                this.onPopShown()
            } else {
                this.onPopHidden()
            }
        }
    },
    methods: {
        getTargetEl() {
            return utils.getEl(this.$refs.target)
        },
        getPopEl() {
            return utils.getEl(this.$refs.pop)
        },
        addEventListener() {
            window.document.addEventListener('click', this.onDocumentClick)
            if (this.escToClose) {
                window.document.addEventListener('keydown', this.onDocumentKeydown)
            }
        },
        removeEventListener() {
            window.document.removeEventListener('click', this.onDocumentClick)
            if (this.escToClose) {
                window.document.removeEventListener('keydown', this.onDocumentKeydown)
            }
        },
        onDocumentClick(e) {
            let targetEl = this.getTargetEl()
            let popEl = this.getPopEl()

            if (
                popEl.contains(e.target)
                || targetEl.contains(e.target)
                || !window.document.contains(e.target)
                || e.target.classList.contains('c-scrollbar')
            ) {
                return
            }
            this.hidePop()
        },
        onDocumentKeydown(e) {
            if (e.keyCode == 27 && popIdUtil.isTop(this.popId)) {
                this.hidePop()
            }
        },
        onPopShown() {
            if (this.escToClose) {
                this.popId = popIdUtil.create()
            }
            this.$nextTick(() => {
                this.pinToTarget()

                this.addEventListener()
            })
        },
        onPopHidden() {
            this.removeEventListener()

            popIdUtil.remove(this.popId)

            this.resizeObserver.disconnect()

            if (this.popInstance) {
                this.popInstance.destroy()
            }
        },
        hidePop() {
            this.$emit('update:popShown', false)
        },
        pinToTarget() {
            let popEl = this.getPopEl()
            if (!popEl) {
                return
            }

            this.resizeObserver.observe(popEl)

            let targetEl = this.getTargetEl()

            if (this.useTargetWidth) {
                let targetRect = targetEl.getBoundingClientRect()
                popEl.style.width = targetRect.width + 'px'
            }

            if (this.popInstance) {
                this.popInstance.destroy()
            }
            let popModifiers = this.popModifiers
            if (this.getPopModifiersFunc) {
                popModifiers = this.getPopModifiersFunc()
            }
            this.popInstance = createPopper(targetEl, popEl, {
                strategy: 'fixed',
                placement: this.popPlacement,
                modifiers: popModifiers
            })
        },
    },
    unmounted() {
        this.onPopHidden()
    }
}
</script>